#pragma once

#include "mockif.hpp"
#include "trigger.hpp"
#include "types.h"

namespace Trade {

enum CASE_CONFUSED : case_t
{
  CASE_CNFSD_NO = 0x0,
  CASE_CNFSD_FORCE_NEAR_FAR = 0x1,
  CASE_CNFSD_PREDICTED_NEAR_FAR = 0x2,
  CASE_CNFSD_SOLVED_FORCE_NEAR = 0x4,
};

enum class SHOULD_STOP_TOM : case_t
{
  UNKNOW,
  STOP_TOM,
  DEDUCE_POSITION,
  DO_NOTHIGN,
};

struct TJM;
struct MoneyTree;

struct Strategy
{
  Strategy(MoneyTree* mt, TJM* tjm) noexcept
    : vol_per_unit(1)
    , min_vol_in_hand(1)
    , mt(mt)
    , tjm(tjm)
  {
  }

  virtual ~Strategy() {}

  dir_t dir = 0;
  int vol_per_unit = 0;
  int min_vol_in_hand = 0;

  MoneyTree* mt = nullptr;
  TJM* tjm = nullptr;

  void set_volume_params(const int vpu, const int min_vol) noexcept
  {
    vol_per_unit = vpu;
    min_vol_in_hand = min_vol;
  }
  risk_t estimate_this_dir_risk(const dir_t dn, const case_t confused) noexcept;
  price_t get_current_revune() noexcept;
  case_t retrive_confused_case() const noexcept;
  bool is_near_golden_point(const dir_t d,
                            const Lines* l,
                            const price_t hp) const noexcept;
  bool is_near_oppo_line2(const dir_t d,
                          const Lines& l,
                          const price_t hp) const noexcept;
  int close_position(const int part_of_all) noexcept;
  

  virtual int money_tree() noexcept = 0;

  virtual bool is_good_enter_spot(const dir_t d) const noexcept = 0;
  virtual bool is_good_expected_space(const dir_t d,
                                      const bool good_enter) const noexcept = 0;
  virtual bool is_good_timer(const dir_t d, const time_t ts) const noexcept = 0;
  virtual bool reached_target_space(const dir_t d) const noexcept = 0;
  virtual bool visual_dir_against_dir(const dir_t d) const noexcept = 0;
  virtual bool is_strong_opportunity(const dir_t d) const noexcept = 0;

  virtual price_t calculate_reduce_price() noexcept = 0;
  virtual price_t calculate_close_price() noexcept = 0;
  virtual price_t calculate_min_win_price() noexcept = 0;
  virtual price_t calculate_stop_win_price() noexcept = 0;
  virtual price_t calculate_stop_loss_price() noexcept = 0;
  virtual bool risk_is_good_to_me(const price_t risk) const noexcept = 0;

  virtual int jerry_in_dangerous() noexcept = 0;

  virtual int tom_run(const dir_t d, const price_t enter) noexcept = 0;
  virtual int jerry_run(const dir_t d, const price_t enter) noexcept = 0;
  virtual int mickey_run(const dir_t d, const price_t enter) noexcept = 0;
  virtual int tom_stop() noexcept = 0;
  virtual int jerry_stop() noexcept = 0;
  virtual int mickey_stop() noexcept = 0;

  // return the volume
  virtual int should_add_position() noexcept = 0;
  virtual int should_deduce_position() noexcept = 0;
  virtual int get_open_volume() noexcept = 0;
  virtual int get_close_volume() noexcept = 0;

  virtual bool should_close_all_position() noexcept = 0;
  virtual bool can_i_safe_myself() noexcept = 0;
  virtual int safe_me_please() noexcept = 0;

  virtual event_t on_order_open(const OrderPtr& o,
                                const DealPtr& deal) noexcept = 0;
  virtual event_t on_order_close(const OrderPtr& o,
                                 const DealPtr& deal) noexcept = 0;

  virtual int earned_good_enough_space(const dir_t d) const noexcept = 0;
  virtual int pet_time_outed(const dir_t d) const noexcept = 0;

  virtual int on_open(const Trigger* trigger) noexcept = 0;
  virtual int on_close(const Trigger* trigger) noexcept = 0;
  virtual int on_close_stop_win(const Trigger* trigger) noexcept = 0;
  virtual int on_close_stop_loss(const Trigger* trigger) noexcept = 0;
  virtual int on_close_min_win(const Trigger* trigger) noexcept = 0;

  virtual int on_mark_price_up(const Trigger* trigger) noexcept = 0;
  virtual int on_mark_price_dn(const Trigger* trigger) noexcept = 0;
  virtual int on_mark_timer_out(const Trigger* trigger) noexcept = 0;
};

#define MOCKIF (tjm->mockif)
#define VO (mt->vo)
#define HPNOW (mt->hp_now)
#define TMNOW (mt->t_now)
#define IDX (mt->idx)

#define DIR_TJM (mt->vo->dir_tjm)
#define DIR_FORCE (mt->vo->dir_force)
#define DIR_OPPOR (mt->vo->dir_opportunity)
#define VAL_OPPOR (mt->vo->oppor_trend.get_cur_percent())
#define BLINES (mt->better_lines)
#define DIR_MDA (mt->vo->dir_mda)
#define VO_MMA (mt->vo->mma)

#define MT_EVENT (mt->mt_event)
#define TOM (tjm->tom)
#define JERRY (tjm->jerry)
#define MICKEY (tjm->mickey)
#define TOM_DIR (tjm->tom.get_dir())
#define JERRY_DIR (tjm->jerry.get_dir())
#define MICKEY_DIR (tjm->mickey.get_dir())
#define TM_NEAR (mt->tm_near)

#define TRIGGERS (mt->triggers)

} // namespace Trade
